/*
 * Created on Jun 5, 2006
 */
package ar.edu.utn.frba.gdaia.src.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import ar.edu.utn.frba.gdaia.src.domain.Concepto;
import ar.edu.utn.frba.gdaia.src.domain.Regla;
import ar.edu.utn.frba.gdaia.src.domain.Situacion;

/**
 * @author Patricio En esta clase se encapsulan los algoritmos para ordenar las
 *         reglas a aplicarse
 * 
 */
public class IntelligentSort {

	/**
	 * Obtiene la regla de mayor valor de acuerdo a que tanto la situacion
	 * inicial de la regla se aproxima a la situacion actual del cerebro. Notar
	 * que el caso optimo es que la situacion actual de la regla sea EXACTAMENTE
	 * IGUAL a la situacion actual del cerebro.
	 * 
	 * @param reglasExternas
	 *            Reglas externas que son las que aprendio el cerebro.
	 * @param situacionActual
	 *            Situacion Actual del cerebro.
	 * @return la regla de mayor ponderacion.
	 */
	public static Regla sort(List reglasExternas, Situacion situacionActual) {

		long maximoValor = -10000000;
		Regla reglaMaximoValor = null;

		// busca los conceptos menos usados en reglas pertenecientes a la
		// situacion actual
		List conceptosMenosUsados = getConceptosMenosUsados(situacionActual);

		long valor = 0;
		// itero cada regla para valorizarlas.
		for (Iterator it = reglasExternas.iterator(); it.hasNext();) {
			Regla regla = (Regla) it.next();
			// sumo la valorizacion si cada concepto de la sit de la regla esta
			// en la sit interna
			valor = valorarRegla(situacionActual, regla, conceptosMenosUsados);

			// me quedo con la regla de mayor valor. OJO. Me estoy quedando con
			// la primer regla
			// si aparece otra con igual valor, no la tengo en cuento porque la
			// comparacion es por >
			if (valor > maximoValor) {
				maximoValor = valor;
				reglaMaximoValor = regla;
			}

			valor = 0;
		}
		return reglaMaximoValor;
	}

	/**
	 * retorna los conceptos menos usados en la situacion
	 * 
	 * @param situacionActual
	 * @return
	 */
	private static List getConceptosMenosUsados(Situacion situacionActual) {
		List<Concepto> menosUsados = new ArrayList<Concepto>();
		long minimo = 9999999;
		for (Iterator it = situacionActual.getEstado().iterator(); it.hasNext();) {
			Concepto concepto = (Concepto) it.next();
			if (concepto.getPopularidad() < minimo) {
				menosUsados.clear();
				menosUsados.add(concepto);
				minimo = concepto.getPopularidad();
			}
			if (concepto.getPopularidad() == minimo)
				menosUsados.add(concepto);
		}
		return menosUsados;
	}

	/**
	 * 
	 * Suma 3 por cada concepto contenido en la situacion inicial de la regla.
	 * Resta 2 si el concepto no esta presenta en la situacion inicial de la
	 * Resta 5 si el concepto de la regla , no esta contenido en el conjunto de
	 * conceptos de la situacionActual. (Tiene que ver con CUAN especifica es la
	 * regla) regla. NOTA: Estos son valores heuristicos que pueden ser
	 * modificados.
	 * 
	 * @param situacionActual
	 * @param regla
	 * @param conceptosMenosUsados
	 * @return
	 */
	private static long valorarRegla(Situacion situacionActual, Regla regla,
			List conceptosMenosUsados) {
		long valor = 0;
		for (Iterator it = situacionActual.getEstado().iterator(); it.hasNext();) {
			Concepto concepto = (Concepto) it.next();
			if (regla.getSituacionInicial().getEstado().contains(concepto))
				valor += 3;
			else
				valor -= 2;
		}
		for (Iterator it = regla.getSituacionFinal().getEstado().iterator(); it
				.hasNext();) {
			Concepto conceptoDeRegla = (Concepto) it.next();
			if (!situacionActual.getEstado().contains(conceptoDeRegla))
				valor -= 5;
		}
		// se suma 6 por cada concepto menos usado encontrado en la sit inicial
		// de la regla
		for (Iterator it = conceptosMenosUsados.iterator(); it.hasNext();) {
			Concepto conceptoMenosUsado = (Concepto) it.next();
			if (regla.getSituacionInicial().getEstado().contains(
					conceptoMenosUsado))
				valor += 6;
		}

		return valor;
	}

}
